{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "a84dbf4f-f367-4a78-b67f-b2fe7e703be0",
   "metadata": {},
   "source": [
    "## 线性回归"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c4c2a469-d1b2-4b5b-9049-3024016ffdf3",
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.linear_model import LinearRegression#导入线性回归模型\n",
    "import matplotlib.pyplot as plt#绘图库\n",
    "import numpy as np"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5b1553cc-8f23-4419-8925-3173dce87b61",
   "metadata": {},
   "outputs": [],
   "source": [
    "x = np.array([121, 125, 131, 141, 152, 161]).reshape(-1,1)#x是房屋面积，作为特征\n",
    "y = np.array([300, 350, 425, 405,496,517])#y是房屋的\n",
    "plt.scatter(x,y)\n",
    "plt.xlabel(\"area\")#添加横坐标面积\n",
    "plt.ylabel(\"price\")#添加纵坐标价格\n",
    "plt.show()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1a5781be-a174-4a15-a3a9-08f38b4239ba",
   "metadata": {},
   "outputs": [],
   "source": [
    "lr = LinearRegression()#将线性回归模型封装为对象\n",
    "lr.fit(x,y)#模型在数据上训练\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "39fcb563-9112-43f2-9529-886389f6504c",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 模型的可视化\n",
    "\n",
    "w = lr.coef_#存储模型的斜率\n",
    "b = lr.intercept_#存储模型的截距\n",
    "print('斜率:',w)\n",
    "print('截距:',b)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3948c20d-63ba-45ef-ac8d-0b248f654ea5",
   "metadata": {},
   "outputs": [],
   "source": [
    "plt.scatter(x,y)\n",
    "plt.xlabel(\"area\")#添加横坐标面积\n",
    "plt.ylabel(\"price\")#添加纵坐标价格\n",
    "plt.plot([x[0],x[-1]],[x[0]*w+b,x[-1]*w+b])\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "24d1c1f0-ae4e-4c7d-a9df-e1f64c0f63d6",
   "metadata": {},
   "outputs": [],
   "source": [
    "testX = np.array([[130]])#测试样本，面积为130\n",
    "lr.predict(testX)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "32746f8f-ff41-4e71-be2d-a8bfee00c3da",
   "metadata": {},
   "source": [
    "## 线性回归算法实现（扩展）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c3977963-4df4-45fa-83fe-587993c70d27",
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8f917616-962f-495a-863c-188ba3b34b6e",
   "metadata": {},
   "outputs": [],
   "source": [
    "def generate_gradient(X, theta, y):\n",
    "    sample_count = X.shape[0]\n",
    "    # 计算梯度，采用矩阵计算 1/m ∑(((h(x^i)-y^i)) x_j^i)\n",
    "    return (1./sample_count)*X.T.dot(X.dot(theta)-y)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5b716b2f-f72e-498d-84ff-75dacbf01c27",
   "metadata": {},
   "outputs": [],
   "source": [
    "def get_training_data(file_path):\n",
    "    orig_data = np.loadtxt(file_path,skiprows=1) #忽略第一行的标题\n",
    "    cols = orig_data.shape[1]\n",
    "    return (orig_data, orig_data[:, :cols - 1], orig_data[:, cols-1:])\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "bbb917fb-d66e-4944-af48-21b29b4406f7",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 初始化θ数组\n",
    "def init_theta(feature_count):\n",
    "    return np.ones(feature_count).reshape(feature_count, 1)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ff451873-8dbf-4c63-b9c0-6892fd5bf291",
   "metadata": {},
   "outputs": [],
   "source": [
    "def gradient_descending(X, y, theta, alpha):\n",
    "    Jthetas= []  # 记录代价函数J(θ)的变化趋势，验证梯度下降是否运行正确\n",
    "    # 计算损失函数，等于真实值与预测值差的平方。(y^i-h(x^i))^2\n",
    "    Jtheta = (X.dot(theta)-y).T.dot(X.dot(theta)-y)\n",
    "    index = 0\n",
    "    gradient = generate_gradient(X, theta, y) #计算梯度\n",
    "    while not np.all(np.absolute(gradient) <= 1e-5):  #梯度小于0.00001时计算结束\n",
    "        theta = theta - alpha * gradient\n",
    "        gradient = generate_gradient(X, theta, y) #计算新梯度\n",
    "        # 计算损失函数，等于真实值与预测值差的平方(y^i-h(x^i))^2\n",
    "        Jtheta = (X.dot(theta)-y).T.dot(X.dot(theta)-y)\n",
    "        if (index+1) % 10 == 0:\n",
    "            Jthetas.append((index, Jtheta[0]))  #每10次计算记录一次结果\n",
    "        index += 1\n",
    "    return theta,Jthetas\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a7909891-b662-4682-b0e2-3808331ffb90",
   "metadata": {},
   "outputs": [],
   "source": [
    "#展示损失函数变化曲线图\n",
    "def showJTheta(diff_value):\n",
    "    p_x = []\n",
    "    p_y = []\n",
    "    for (index, sum) in diff_value:\n",
    "        p_x.append(index)\n",
    "        p_y.append(sum)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4f53e47e-a3a3-4edd-b66d-8f0e86df691e",
   "metadata": {},
   "outputs": [],
   "source": [
    "#展示实际数据点以及拟合出的曲线图\n",
    "def showlinercurve(theta, sample_training_set):\n",
    "    x, y = sample_training_set[:, 1], sample_training_set[:, 2]\n",
    "    z = theta[0] + theta[1] * x\n",
    "    plt.scatter(x, y, color='b', marker='x',label=\"sample data\")\n",
    "    plt.plot(x, z, 'r', color=\"r\",label=\"regression curve\")\n",
    "    plt.xlabel('x')\n",
    "    plt.ylabel('y')\n",
    "    plt.title('liner regression curve')\n",
    "    plt.legend()\n",
    "    plt.show()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "dc2433a7-3232-49da-8b27-19f4b8554a42",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 读取数据集\n",
    "training_data_include_y, training_x, y = get_training_data(\"./ML/02/lr2_data.txt\")\n",
    "# 获取数据集数量及特征数\n",
    "sample_count, feature_count = training_x.shape\n",
    "# 定义学习步长α\n",
    "alpha = 0.01\n",
    "# 初始化Ɵ\n",
    "theta = init_theta(feature_count)\n",
    "# 获取最终的参数Ɵ及代价\n",
    "result_theta,Jthetas = gradient_descending(training_x, y, theta, alpha)\n",
    "# 打印参数\n",
    "print(\"w:{}\".format(result_theta[0][0]),\"b:{}\".format(result_theta[1][0]))\n",
    "showJTheta(Jthetas)\n",
    "showlinercurve(result_theta, training_data_include_y)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7e1d7da5-1ad7-40ce-a15b-11d8210a5233",
   "metadata": {},
   "source": [
    "## 逻辑回归"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "e7352441-3d00-4536-b3a1-155762ac9094",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 从sklearn.preprocessing里导入StandardScaler。\n",
    "from sklearn.preprocessing import StandardScaler\n",
    "# 从sklearn.linear_model里导入LogisticRegression\n",
    "from sklearn.linear_model import LogisticRegression\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "2eead903-d4db-4f04-9fe6-68a757e7a72a",
   "metadata": {},
   "outputs": [],
   "source": [
    "# X：每一项表示租金和面积\n",
    "# y：表示是否租赁该房间（0：不租，1：租）\n",
    "X=[[2200,15],[2750,20],[5000,40],[4000,20],[3300,20],[2000,10],[2500,12],[12000,80],\n",
    "   [2880,10],[2300,15],[1500,10],[3000,8],[2000,14],[2000,10],[2150,8],[3400,20],\n",
    "   [5000,20],[4000,10],[3300,15],[2000,12],[2500,14],[10000,100],[3150,10],\n",
    "   [2950,15],[1500,5],[3000,18],[8000,12],[2220,14],[6000,100],[3050,10]\n",
    "  ]\n",
    "\n",
    "y=[1,1,0,0,1,1,1,1,0,1,1,0,1,1,0,1,0,0,0,1,1,1,0,1,0,1,0,1,1,0]\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "f692668a-59d6-4666-b2da-84c00e449138",
   "metadata": {},
   "outputs": [],
   "source": [
    "ss = StandardScaler()\n",
    "X_train = ss.fit_transform(X)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "ca18ad2e-dfcc-49ea-8436-a315ef7283e6",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[-0.60583897 -0.29313058]\n",
      " [-0.37682768 -0.09050576]\n",
      " [ 0.56003671  0.71999355]\n",
      " [ 0.14365254 -0.09050576]\n",
      " [-0.14781638 -0.09050576]\n",
      " [-0.68911581 -0.49575541]\n",
      " [-0.48092372 -0.41470548]\n",
      " [ 3.47472592  2.34099218]\n",
      " [-0.32269773 -0.49575541]\n",
      " [-0.56420055 -0.29313058]\n",
      " [-0.89730789 -0.49575541]\n",
      " [-0.27273163 -0.57680534]\n",
      " [-0.68911581 -0.33365555]\n",
      " [-0.68911581 -0.49575541]\n",
      " [-0.62665818 -0.57680534]\n",
      " [-0.10617796 -0.09050576]\n",
      " [ 0.56003671 -0.09050576]\n",
      " [ 0.14365254 -0.49575541]\n",
      " [-0.14781638 -0.29313058]\n",
      " [-0.68911581 -0.41470548]\n",
      " [-0.48092372 -0.33365555]\n",
      " [ 2.64195758  3.15149149]\n",
      " [-0.21027401 -0.49575541]\n",
      " [-0.29355084 -0.29313058]\n",
      " [-0.89730789 -0.69838024]\n",
      " [-0.27273163 -0.17155569]\n",
      " [ 1.80918923 -0.41470548]\n",
      " [-0.59751129 -0.33365555]\n",
      " [ 0.97642089  3.15149149]\n",
      " [-0.25191242 -0.49575541]]\n"
     ]
    }
   ],
   "source": [
    "print(X_train)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "c20c1b4f-e933-4104-b958-cdee066182dc",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<style>#sk-container-id-1 {\n",
       "  /* Definition of color scheme common for light and dark mode */\n",
       "  --sklearn-color-text: black;\n",
       "  --sklearn-color-line: gray;\n",
       "  /* Definition of color scheme for unfitted estimators */\n",
       "  --sklearn-color-unfitted-level-0: #fff5e6;\n",
       "  --sklearn-color-unfitted-level-1: #f6e4d2;\n",
       "  --sklearn-color-unfitted-level-2: #ffe0b3;\n",
       "  --sklearn-color-unfitted-level-3: chocolate;\n",
       "  /* Definition of color scheme for fitted estimators */\n",
       "  --sklearn-color-fitted-level-0: #f0f8ff;\n",
       "  --sklearn-color-fitted-level-1: #d4ebff;\n",
       "  --sklearn-color-fitted-level-2: #b3dbfd;\n",
       "  --sklearn-color-fitted-level-3: cornflowerblue;\n",
       "\n",
       "  /* Specific color for light theme */\n",
       "  --sklearn-color-text-on-default-background: var(--sg-text-color, var(--theme-code-foreground, var(--jp-content-font-color1, black)));\n",
       "  --sklearn-color-background: var(--sg-background-color, var(--theme-background, var(--jp-layout-color0, white)));\n",
       "  --sklearn-color-border-box: var(--sg-text-color, var(--theme-code-foreground, var(--jp-content-font-color1, black)));\n",
       "  --sklearn-color-icon: #696969;\n",
       "\n",
       "  @media (prefers-color-scheme: dark) {\n",
       "    /* Redefinition of color scheme for dark theme */\n",
       "    --sklearn-color-text-on-default-background: var(--sg-text-color, var(--theme-code-foreground, var(--jp-content-font-color1, white)));\n",
       "    --sklearn-color-background: var(--sg-background-color, var(--theme-background, var(--jp-layout-color0, #111)));\n",
       "    --sklearn-color-border-box: var(--sg-text-color, var(--theme-code-foreground, var(--jp-content-font-color1, white)));\n",
       "    --sklearn-color-icon: #878787;\n",
       "  }\n",
       "}\n",
       "\n",
       "#sk-container-id-1 {\n",
       "  color: var(--sklearn-color-text);\n",
       "}\n",
       "\n",
       "#sk-container-id-1 pre {\n",
       "  padding: 0;\n",
       "}\n",
       "\n",
       "#sk-container-id-1 input.sk-hidden--visually {\n",
       "  border: 0;\n",
       "  clip: rect(1px 1px 1px 1px);\n",
       "  clip: rect(1px, 1px, 1px, 1px);\n",
       "  height: 1px;\n",
       "  margin: -1px;\n",
       "  overflow: hidden;\n",
       "  padding: 0;\n",
       "  position: absolute;\n",
       "  width: 1px;\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-dashed-wrapped {\n",
       "  border: 1px dashed var(--sklearn-color-line);\n",
       "  margin: 0 0.4em 0.5em 0.4em;\n",
       "  box-sizing: border-box;\n",
       "  padding-bottom: 0.4em;\n",
       "  background-color: var(--sklearn-color-background);\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-container {\n",
       "  /* jupyter's `normalize.less` sets `[hidden] { display: none; }`\n",
       "     but bootstrap.min.css set `[hidden] { display: none !important; }`\n",
       "     so we also need the `!important` here to be able to override the\n",
       "     default hidden behavior on the sphinx rendered scikit-learn.org.\n",
       "     See: https://github.com/scikit-learn/scikit-learn/issues/21755 */\n",
       "  display: inline-block !important;\n",
       "  position: relative;\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-text-repr-fallback {\n",
       "  display: none;\n",
       "}\n",
       "\n",
       "div.sk-parallel-item,\n",
       "div.sk-serial,\n",
       "div.sk-item {\n",
       "  /* draw centered vertical line to link estimators */\n",
       "  background-image: linear-gradient(var(--sklearn-color-text-on-default-background), var(--sklearn-color-text-on-default-background));\n",
       "  background-size: 2px 100%;\n",
       "  background-repeat: no-repeat;\n",
       "  background-position: center center;\n",
       "}\n",
       "\n",
       "/* Parallel-specific style estimator block */\n",
       "\n",
       "#sk-container-id-1 div.sk-parallel-item::after {\n",
       "  content: \"\";\n",
       "  width: 100%;\n",
       "  border-bottom: 2px solid var(--sklearn-color-text-on-default-background);\n",
       "  flex-grow: 1;\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-parallel {\n",
       "  display: flex;\n",
       "  align-items: stretch;\n",
       "  justify-content: center;\n",
       "  background-color: var(--sklearn-color-background);\n",
       "  position: relative;\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-parallel-item {\n",
       "  display: flex;\n",
       "  flex-direction: column;\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-parallel-item:first-child::after {\n",
       "  align-self: flex-end;\n",
       "  width: 50%;\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-parallel-item:last-child::after {\n",
       "  align-self: flex-start;\n",
       "  width: 50%;\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-parallel-item:only-child::after {\n",
       "  width: 0;\n",
       "}\n",
       "\n",
       "/* Serial-specific style estimator block */\n",
       "\n",
       "#sk-container-id-1 div.sk-serial {\n",
       "  display: flex;\n",
       "  flex-direction: column;\n",
       "  align-items: center;\n",
       "  background-color: var(--sklearn-color-background);\n",
       "  padding-right: 1em;\n",
       "  padding-left: 1em;\n",
       "}\n",
       "\n",
       "\n",
       "/* Toggleable style: style used for estimator/Pipeline/ColumnTransformer box that is\n",
       "clickable and can be expanded/collapsed.\n",
       "- Pipeline and ColumnTransformer use this feature and define the default style\n",
       "- Estimators will overwrite some part of the style using the `sk-estimator` class\n",
       "*/\n",
       "\n",
       "/* Pipeline and ColumnTransformer style (default) */\n",
       "\n",
       "#sk-container-id-1 div.sk-toggleable {\n",
       "  /* Default theme specific background. It is overwritten whether we have a\n",
       "  specific estimator or a Pipeline/ColumnTransformer */\n",
       "  background-color: var(--sklearn-color-background);\n",
       "}\n",
       "\n",
       "/* Toggleable label */\n",
       "#sk-container-id-1 label.sk-toggleable__label {\n",
       "  cursor: pointer;\n",
       "  display: block;\n",
       "  width: 100%;\n",
       "  margin-bottom: 0;\n",
       "  padding: 0.5em;\n",
       "  box-sizing: border-box;\n",
       "  text-align: center;\n",
       "}\n",
       "\n",
       "#sk-container-id-1 label.sk-toggleable__label-arrow:before {\n",
       "  /* Arrow on the left of the label */\n",
       "  content: \"▸\";\n",
       "  float: left;\n",
       "  margin-right: 0.25em;\n",
       "  color: var(--sklearn-color-icon);\n",
       "}\n",
       "\n",
       "#sk-container-id-1 label.sk-toggleable__label-arrow:hover:before {\n",
       "  color: var(--sklearn-color-text);\n",
       "}\n",
       "\n",
       "/* Toggleable content - dropdown */\n",
       "\n",
       "#sk-container-id-1 div.sk-toggleable__content {\n",
       "  max-height: 0;\n",
       "  max-width: 0;\n",
       "  overflow: hidden;\n",
       "  text-align: left;\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-unfitted-level-0);\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-toggleable__content.fitted {\n",
       "  /* fitted */\n",
       "  background-color: var(--sklearn-color-fitted-level-0);\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-toggleable__content pre {\n",
       "  margin: 0.2em;\n",
       "  border-radius: 0.25em;\n",
       "  color: var(--sklearn-color-text);\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-unfitted-level-0);\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-toggleable__content.fitted pre {\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-fitted-level-0);\n",
       "}\n",
       "\n",
       "#sk-container-id-1 input.sk-toggleable__control:checked~div.sk-toggleable__content {\n",
       "  /* Expand drop-down */\n",
       "  max-height: 200px;\n",
       "  max-width: 100%;\n",
       "  overflow: auto;\n",
       "}\n",
       "\n",
       "#sk-container-id-1 input.sk-toggleable__control:checked~label.sk-toggleable__label-arrow:before {\n",
       "  content: \"▾\";\n",
       "}\n",
       "\n",
       "/* Pipeline/ColumnTransformer-specific style */\n",
       "\n",
       "#sk-container-id-1 div.sk-label input.sk-toggleable__control:checked~label.sk-toggleable__label {\n",
       "  color: var(--sklearn-color-text);\n",
       "  background-color: var(--sklearn-color-unfitted-level-2);\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-label.fitted input.sk-toggleable__control:checked~label.sk-toggleable__label {\n",
       "  background-color: var(--sklearn-color-fitted-level-2);\n",
       "}\n",
       "\n",
       "/* Estimator-specific style */\n",
       "\n",
       "/* Colorize estimator box */\n",
       "#sk-container-id-1 div.sk-estimator input.sk-toggleable__control:checked~label.sk-toggleable__label {\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-unfitted-level-2);\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-estimator.fitted input.sk-toggleable__control:checked~label.sk-toggleable__label {\n",
       "  /* fitted */\n",
       "  background-color: var(--sklearn-color-fitted-level-2);\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-label label.sk-toggleable__label,\n",
       "#sk-container-id-1 div.sk-label label {\n",
       "  /* The background is the default theme color */\n",
       "  color: var(--sklearn-color-text-on-default-background);\n",
       "}\n",
       "\n",
       "/* On hover, darken the color of the background */\n",
       "#sk-container-id-1 div.sk-label:hover label.sk-toggleable__label {\n",
       "  color: var(--sklearn-color-text);\n",
       "  background-color: var(--sklearn-color-unfitted-level-2);\n",
       "}\n",
       "\n",
       "/* Label box, darken color on hover, fitted */\n",
       "#sk-container-id-1 div.sk-label.fitted:hover label.sk-toggleable__label.fitted {\n",
       "  color: var(--sklearn-color-text);\n",
       "  background-color: var(--sklearn-color-fitted-level-2);\n",
       "}\n",
       "\n",
       "/* Estimator label */\n",
       "\n",
       "#sk-container-id-1 div.sk-label label {\n",
       "  font-family: monospace;\n",
       "  font-weight: bold;\n",
       "  display: inline-block;\n",
       "  line-height: 1.2em;\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-label-container {\n",
       "  text-align: center;\n",
       "}\n",
       "\n",
       "/* Estimator-specific */\n",
       "#sk-container-id-1 div.sk-estimator {\n",
       "  font-family: monospace;\n",
       "  border: 1px dotted var(--sklearn-color-border-box);\n",
       "  border-radius: 0.25em;\n",
       "  box-sizing: border-box;\n",
       "  margin-bottom: 0.5em;\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-unfitted-level-0);\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-estimator.fitted {\n",
       "  /* fitted */\n",
       "  background-color: var(--sklearn-color-fitted-level-0);\n",
       "}\n",
       "\n",
       "/* on hover */\n",
       "#sk-container-id-1 div.sk-estimator:hover {\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-unfitted-level-2);\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-estimator.fitted:hover {\n",
       "  /* fitted */\n",
       "  background-color: var(--sklearn-color-fitted-level-2);\n",
       "}\n",
       "\n",
       "/* Specification for estimator info (e.g. \"i\" and \"?\") */\n",
       "\n",
       "/* Common style for \"i\" and \"?\" */\n",
       "\n",
       ".sk-estimator-doc-link,\n",
       "a:link.sk-estimator-doc-link,\n",
       "a:visited.sk-estimator-doc-link {\n",
       "  float: right;\n",
       "  font-size: smaller;\n",
       "  line-height: 1em;\n",
       "  font-family: monospace;\n",
       "  background-color: var(--sklearn-color-background);\n",
       "  border-radius: 1em;\n",
       "  height: 1em;\n",
       "  width: 1em;\n",
       "  text-decoration: none !important;\n",
       "  margin-left: 1ex;\n",
       "  /* unfitted */\n",
       "  border: var(--sklearn-color-unfitted-level-1) 1pt solid;\n",
       "  color: var(--sklearn-color-unfitted-level-1);\n",
       "}\n",
       "\n",
       ".sk-estimator-doc-link.fitted,\n",
       "a:link.sk-estimator-doc-link.fitted,\n",
       "a:visited.sk-estimator-doc-link.fitted {\n",
       "  /* fitted */\n",
       "  border: var(--sklearn-color-fitted-level-1) 1pt solid;\n",
       "  color: var(--sklearn-color-fitted-level-1);\n",
       "}\n",
       "\n",
       "/* On hover */\n",
       "div.sk-estimator:hover .sk-estimator-doc-link:hover,\n",
       ".sk-estimator-doc-link:hover,\n",
       "div.sk-label-container:hover .sk-estimator-doc-link:hover,\n",
       ".sk-estimator-doc-link:hover {\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-unfitted-level-3);\n",
       "  color: var(--sklearn-color-background);\n",
       "  text-decoration: none;\n",
       "}\n",
       "\n",
       "div.sk-estimator.fitted:hover .sk-estimator-doc-link.fitted:hover,\n",
       ".sk-estimator-doc-link.fitted:hover,\n",
       "div.sk-label-container:hover .sk-estimator-doc-link.fitted:hover,\n",
       ".sk-estimator-doc-link.fitted:hover {\n",
       "  /* fitted */\n",
       "  background-color: var(--sklearn-color-fitted-level-3);\n",
       "  color: var(--sklearn-color-background);\n",
       "  text-decoration: none;\n",
       "}\n",
       "\n",
       "/* Span, style for the box shown on hovering the info icon */\n",
       ".sk-estimator-doc-link span {\n",
       "  display: none;\n",
       "  z-index: 9999;\n",
       "  position: relative;\n",
       "  font-weight: normal;\n",
       "  right: .2ex;\n",
       "  padding: .5ex;\n",
       "  margin: .5ex;\n",
       "  width: min-content;\n",
       "  min-width: 20ex;\n",
       "  max-width: 50ex;\n",
       "  color: var(--sklearn-color-text);\n",
       "  box-shadow: 2pt 2pt 4pt #999;\n",
       "  /* unfitted */\n",
       "  background: var(--sklearn-color-unfitted-level-0);\n",
       "  border: .5pt solid var(--sklearn-color-unfitted-level-3);\n",
       "}\n",
       "\n",
       ".sk-estimator-doc-link.fitted span {\n",
       "  /* fitted */\n",
       "  background: var(--sklearn-color-fitted-level-0);\n",
       "  border: var(--sklearn-color-fitted-level-3);\n",
       "}\n",
       "\n",
       ".sk-estimator-doc-link:hover span {\n",
       "  display: block;\n",
       "}\n",
       "\n",
       "/* \"?\"-specific style due to the `<a>` HTML tag */\n",
       "\n",
       "#sk-container-id-1 a.estimator_doc_link {\n",
       "  float: right;\n",
       "  font-size: 1rem;\n",
       "  line-height: 1em;\n",
       "  font-family: monospace;\n",
       "  background-color: var(--sklearn-color-background);\n",
       "  border-radius: 1rem;\n",
       "  height: 1rem;\n",
       "  width: 1rem;\n",
       "  text-decoration: none;\n",
       "  /* unfitted */\n",
       "  color: var(--sklearn-color-unfitted-level-1);\n",
       "  border: var(--sklearn-color-unfitted-level-1) 1pt solid;\n",
       "}\n",
       "\n",
       "#sk-container-id-1 a.estimator_doc_link.fitted {\n",
       "  /* fitted */\n",
       "  border: var(--sklearn-color-fitted-level-1) 1pt solid;\n",
       "  color: var(--sklearn-color-fitted-level-1);\n",
       "}\n",
       "\n",
       "/* On hover */\n",
       "#sk-container-id-1 a.estimator_doc_link:hover {\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-unfitted-level-3);\n",
       "  color: var(--sklearn-color-background);\n",
       "  text-decoration: none;\n",
       "}\n",
       "\n",
       "#sk-container-id-1 a.estimator_doc_link.fitted:hover {\n",
       "  /* fitted */\n",
       "  background-color: var(--sklearn-color-fitted-level-3);\n",
       "}\n",
       "</style><div id=\"sk-container-id-1\" class=\"sk-top-container\"><div class=\"sk-text-repr-fallback\"><pre>LogisticRegression()</pre><b>In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook. <br />On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.</b></div><div class=\"sk-container\" hidden><div class=\"sk-item\"><div class=\"sk-estimator fitted sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=\"sk-estimator-id-1\" type=\"checkbox\" checked><label for=\"sk-estimator-id-1\" class=\"sk-toggleable__label fitted sk-toggleable__label-arrow fitted\">&nbsp;&nbsp;LogisticRegression<a class=\"sk-estimator-doc-link fitted\" rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.5/modules/generated/sklearn.linear_model.LogisticRegression.html\">?<span>Documentation for LogisticRegression</span></a><span class=\"sk-estimator-doc-link fitted\">i<span>Fitted</span></span></label><div class=\"sk-toggleable__content fitted\"><pre>LogisticRegression()</pre></div> </div></div></div></div>"
      ],
      "text/plain": [
       "LogisticRegression()"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#调用Lr中的fit模块训练模型参数\n",
    "lr = LogisticRegression()\n",
    "lr.fit(X_train, y)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "76c91f04-ae70-4d50-a822-e931db59bd93",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "待预测的值： [[-0.68911581 -0.57680534]]\n",
      "predicted label =  [1]\n",
      "probability =  [[0.41882379 0.58117621]]\n"
     ]
    }
   ],
   "source": [
    "testX = [[2000,8]]\n",
    "X_test = ss.transform(testX)\n",
    "print(\"待预测的值：\",X_test)\n",
    "label = lr.predict(X_test)\n",
    "print(\"predicted label = \", label)\n",
    "#输出预测概率\n",
    "prob = lr.predict_proba(X_test)\n",
    "print(\"probability = \",prob)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e7585aea-7118-42ad-8cd6-acee3914ab99",
   "metadata": {},
   "source": [
    "## 决策树"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "dacd5130-e675-459f-b5e0-979d79113fd7",
   "metadata": {},
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "import numpy as np\n",
    "from sklearn import tree\n",
    "import pydotplus\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "442a26d9-2bbd-4693-9019-0f5c89ec1a2e",
   "metadata": {},
   "outputs": [],
   "source": [
    "#生成决策树\n",
    "def createTree(trainingData):\n",
    "    data = trainingData.iloc[:, :-1]  # 特征矩阵\n",
    "    labels = trainingData.iloc[:, -1]  # 标签\n",
    "    trainedTree = tree.DecisionTreeClassifier(criterion=\"entropy\")  # 分类决策树\n",
    "    trainedTree.fit(data, labels)  # 训练\n",
    "    return trainedTree\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d540b96a-c28d-4dd4-83d8-c3a184b0f099",
   "metadata": {},
   "outputs": [],
   "source": [
    "def showtree2pdf(trainedTree,finename):\n",
    "    dot_data = tree.export_graphviz(trainedTree, out_file=None) #将树导出为Graphviz格式\n",
    "    graph = pydotplus.graph_from_dot_data(dot_data)\n",
    "    graph.write_pdf(finename)  #保存树图到本地，格式为pdf\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "98bd70b3-e9f3-4be7-aab0-525e9cba563c",
   "metadata": {},
   "outputs": [],
   "source": [
    "def data2vectoc(data):\n",
    "    names = data.columns[:-1]\n",
    "    for i in names:\n",
    "        col = pd.Categorical(data[i])\n",
    "        data[i] = col.codes\n",
    "    return data\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ab300847-f76e-4369-b022-52ca2093b8a9",
   "metadata": {},
   "outputs": [],
   "source": [
    "data = pd.read_table(\"tennis.txt\",header=None,sep='\\t') #读取训练数据\n",
    "trainingvec=data2vectoc(data) #向量化数据\n",
    "decisionTree=createTree(trainingvec) #创建决策树\n",
    "showtree2pdf(decisionTree,\"tennis.pdf\")  #图示决策树\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e0b6c5c0-28e0-4f84-838a-3edc29b50940",
   "metadata": {},
   "outputs": [],
   "source": [
    "testVec = [0,0,1,1] # 天气晴、气温冷、湿度高、风力强\n",
    "print(decisionTree.predict(np.array(testVec).reshape(1,-1))) #预测\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "81da3d87-9ee9-431a-b223-07b1758e7dcc",
   "metadata": {},
   "source": [
    "## 朴素贝叶斯"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "66ae7117-3640-4047-abd6-7ee5711c3087",
   "metadata": {},
   "outputs": [],
   "source": [
    "from numpy import *\n",
    "from os import listdir\n",
    "import codecs #字符转换模块，用于文本的编码和解码\n",
    "import jieba#中文分词库\n",
    "import re\n",
    "from sklearn.naive_bayes import MultinomialNB\n",
    "from collections import Counter\n",
    "from itertools import chain #用于串联迭代对象\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "cf964271-6bc6-4195-9c41-7f6acfb1ffe0",
   "metadata": {},
   "outputs": [],
   "source": [
    "def segment2word(doc: str):\n",
    "#从stop_list.txt文件中提取停用词，存储为列表    \n",
    "    stop_words = codecs.open(\"./ML/04/stop_list.txt\", \"r\", \"UTF-8\").read().splitlines()\n",
    "    doc = re.sub('[\\t\\r\\n]', ' ', doc)#去除邮件文本中的缩进，换行等\n",
    "    word_list = list(jieba.cut(doc.strip())) #用jieba进行分词 \n",
    "    out_str = ''\n",
    "    for word in word_list:  #删去邮件文本中的停用词\n",
    "        if word == ' ' or word == '':#\n",
    "            continue\n",
    "        if word not in stop_words:\n",
    "            out_str += word.strip()\n",
    "            out_str += ' '\n",
    "    segments = out_str.strip().split(sep=' ')\n",
    "    return segments\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0b53dd8c-b325-47b3-a895-916c4c7efb42",
   "metadata": {},
   "outputs": [],
   "source": [
    "def getDatafromDir(data_dir):\n",
    "    docLists = []\n",
    "    docLabels = [f for f in listdir(data_dir) if f.endswith('.txt')]#存储每一封邮件的名称\n",
    "    for doc in docLabels:\n",
    "        try:\n",
    "            filepath=data_dir + \"/\" + doc\n",
    "            #对训练集的邮件进行文本处理\n",
    "            wordList = segment2word(codecs.open(filepath, \"r\", \"UTF-8\").read())\n",
    "            docLists.append(wordList)#整合训练集的邮件处理后的结果\n",
    "        except:\t\t\n",
    "            print(\"handling file %s is error!!\" %filepath)\n",
    "    return docLists\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "951ef7fc-6fab-4058-b855-828ff4cc9883",
   "metadata": {},
   "outputs": [],
   "source": [
    "spamDocList=getDatafromDir(\"./ML/04/email/spam/\")  #对垃圾邮件进行文本处理\n",
    "hamDocList = getDatafromDir(\"./ML/04/email/ham/\")  #对正常邮件进行文本处理\n",
    "fullDocList = spamDocList + hamDocList#储存邮件的特征\n",
    "# 添加标签，垃圾邮件标记为1，正常邮件标记为0\n",
    "classList = array([1]*len(spamDocList)+[0]*len(hamDocList))\n",
    "frequencyDic = Counter(chain(*fullDocList)) # 生成词频映射词典\n",
    "topWords = [w[0] for w in frequencyDic.most_common(500)] #获取前500个最频繁的热词。\n",
    "vector = []\n",
    "\n",
    "for docList in fullDocList:\n",
    "    #统计每封邮件中每个热词出现的频率\n",
    "    topwords_list = list(map(lambda x: docList.count(x), topWords))\n",
    "    vector.append(topwords_list)\n",
    "\n",
    "#生成vector作为数据特征\n",
    "vector = array(vector)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e5f2fdd3-31fb-4660-9218-52b5c62c952f",
   "metadata": {},
   "outputs": [],
   "source": [
    "model = MultinomialNB()  #选取多项式贝叶斯为训练模型\n",
    "model.fit(vector, classList)  #vector为特征，classlist为标签，训练贝叶斯模型\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "851432b5-8768-413e-b424-603ea856d0cd",
   "metadata": {},
   "outputs": [],
   "source": [
    "#存储每一封训练集邮件的名称\n",
    "dataList=[]\n",
    "test_dir = \"./ML/04/email/spam/\"\n",
    "docLabels = [f for f in listdir(test_dir) if f.endswith('.txt')]\n",
    "\n",
    "#模型推理\n",
    "for doc in docLabels:\n",
    "    try:\n",
    "        filepath = test_dir + \"/\" + doc\n",
    "        dataList = segment2word(codecs.open(filepath, \"r\", \"UTF-8\").read())\n",
    "    except:\n",
    "        print(\"handling file %s is error!!\" % filepath)\n",
    "\n",
    "#统计测试集邮件中的热词的词频，提取特征\n",
    "    testVector = array(tuple(map(lambda x: dataList.count(x), topWords)))\n",
    "testVector_reshape = testVector.reshape(1,-1)\n",
    "\n",
    "\t #特征传入模型进行推理\n",
    "    predicted_label = model.predict(testVector.reshape(1, -1)) \n",
    "    if(predicted_label == 1):\n",
    "        print(\"%s is spam mail\" %doc)\n",
    "    else:\n",
    "        print(\"%s is NOT spam mail\" % doc)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7913c98d-3703-4ad6-ab97-30fe4eed34a6",
   "metadata": {},
   "source": [
    "## k-means"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "17786421-3135-4d58-8d51-356c8f3d306a",
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.datasets import make_blobs\n",
    "import matplotlib.pyplot as plt\n",
    "from sklearn.cluster import KMeans\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8f2b3354-48a8-41a9-9e05-6d96dd965ce0",
   "metadata": {},
   "outputs": [],
   "source": [
    "X, y = make_blobs(n_samples=500,n_features=2,centers=4,random_state=1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "cb28c22b-1d15-4f92-bfb0-beb7587bf0d7",
   "metadata": {},
   "outputs": [],
   "source": [
    "print(\"X的维度为：{}\".format(X.shape))\n",
    "print(\"y的维度为：{}\".format(y.shape))\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b6b0b108-733e-4afd-8291-564354470382",
   "metadata": {},
   "outputs": [],
   "source": [
    "fig, ax1 = plt.subplots(1)\n",
    "ax1.scatter(X[:, 0], X[:, 1]\n",
    "            ,marker='o'  # 设置点的形状为圆形\n",
    "            ,s=8  # 设置点的大小\n",
    "           )\n",
    "plt.show()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "75c4b5af-b686-41fd-9735-84b8f21126f8",
   "metadata": {},
   "outputs": [],
   "source": [
    "color = [\"red\",\"pink\",\"orange\",\"green\"]\n",
    "fig, ax1 = plt.subplots(1)\n",
    "\n",
    "for i in range(4):\n",
    "    ax1.scatter(X[y==i, 0], X[y==i, 1]  # 根据每个点的标签绘制\n",
    "            ,marker='o'  # 设置点的形状为圆形\n",
    "            ,s=8  # 设置点的大小\n",
    "            ,c=color[i]\n",
    "           )\n",
    "plt.show()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "33dfb43d-c4fd-40f4-910c-ad6680e1325b",
   "metadata": {},
   "outputs": [],
   "source": [
    "n_clusters = 3\n",
    "cluster1 = KMeans(n_clusters=n_clusters,random_state=3).fit(X)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0bc13d68-e38d-4938-9842-d36e15d1b197",
   "metadata": {},
   "outputs": [],
   "source": [
    "y_pred1 = cluster1.labels_\n",
    "print(y_pred1)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "bab7a189-c90d-423b-80ed-a749fd2d2ca3",
   "metadata": {},
   "outputs": [],
   "source": [
    "centroid1 = cluster1.cluster_centers_\n",
    "print(centroid1)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3c9021c1-0057-4f3e-a39d-382f80caa1f6",
   "metadata": {},
   "outputs": [],
   "source": [
    "color = [\"red\",\"pink\",\"orange\",\"gray\"]\n",
    "\n",
    "fig, ax1 = plt.subplots(1)\n",
    "\n",
    "for i in range(n_clusters):\n",
    "    ax1.scatter(X[y_pred1==i, 0], X[y_pred1==i, 1]\n",
    "            ,marker='o' #点的形状\n",
    "            ,s=8 #点的大小\n",
    "            ,c=color[i]\n",
    "           )\n",
    "    \n",
    "ax1.scatter(centroid1[:,0],centroid1[:,1]\n",
    "           ,marker=\"x\"\n",
    "           ,s=15\n",
    "           ,c=\"black\")\n",
    "plt.show()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "40a47635-a3c3-4949-a912-38c530fdab54",
   "metadata": {},
   "outputs": [],
   "source": [
    "n_clusters = 4\n",
    "cluster2 = KMeans(n_clusters=n_clusters,random_state=0).fit(X)\n",
    "y_pred2 = cluster2.labels_\n",
    "centroid2 = cluster2.cluster_centers_\n",
    "print(\"质心：{}\".format(centroid2))\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "78df7ec7-2ce5-47a5-8e3f-8e9f21482876",
   "metadata": {},
   "outputs": [],
   "source": [
    "color = [\"red\",\"pink\",\"orange\",\"green\"]\n",
    "\n",
    "fig, ax1 = plt.subplots(1)\n",
    "\n",
    "for i in range(n_clusters):\n",
    "    ax1.scatter(X[y_pred2==i, 0], X[y_pred2==i, 1]\n",
    "            ,marker='o' #点的形状\n",
    "            ,s=8 #点的大小\n",
    "            ,c=color[i]\n",
    "           )\n",
    "    \n",
    "ax1.scatter(centroid2[:,0],centroid2[:,1]\n",
    "           ,marker=\"x\"\n",
    "           ,s=15\n",
    "           ,c=\"black\")\n",
    "plt.show()\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
